#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/7/6 14:55
# @Author : linjinting
# @Project : tableview-model
# @File : tablemodel.py
# @Software: PyCharm


import re
from PySide2.QtCore import QAbstractItemModel, QModelIndex, Qt, QSortFilterProxyModel


class TableModel(QAbstractItemModel):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.m_tableData = list()
        self.m_tableHeader = list()
        self.rootItem = None

    def initData(self, data=None):
        if data is None:
            return
        self.m_tableData = data
        if self.rowCount() == 0:
            return
        self.m_tableHeader = list(self.m_tableData[0].keys())
        # if len(self.m_tableData[0]) > len(header):
        #     for i in range(len(self.m_tableData[0]) - len(header)):
        #         header.append('column %d' % (i + 1))

    def rowCount(self, parent=None):
        return len(self.m_tableData)

    def columnCount(self, parent=None) -> int:
        if self.rowCount() > 0:
            return len(self.m_tableData[0])
        return len(self.m_tableHeader)

    def data(self, index, role=None):
        if not index.isValid() or not 0 <= index.row() < self.rowCount():
            return

        row = index.row()
        col = index.column()

        if role == Qt.DisplayRole or role == Qt.EditRole or role == Qt.ToolTipRole:
            # if col == 0:
            #     return str(row)  # 行号
            # else:
            value = list(self.m_tableData[row].values())[col]
            if isinstance(value, bytes):
                return value.decode()
            return str(value)  # 数据
        # print(index, role)
        # return

    def headerData(self, section: int, orientation, role: int = ...):
        """
        设置表头。
        """
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:  # 限定只更改行表头
                if section + 1 > len(self.m_tableHeader):
                    self.m_tableHeader.append('column %d ' % (section + 1))
                return self.m_tableHeader[section]
            if orientation == Qt.Vertical:
                # print(section)
                return section + 1

    def setData(self, index, data, role=None):
        # 编辑后更新模型中的数据 View中编辑后，View会调用这个方法修改Model中的数据
        if index.isValid() and data:
            row = index.row()
            col = index.column()
            colName = self.m_tableHeader[col]
            self.m_tableData[row][colName] = data
            # col = index.column()
            # print(col)
            # # if 0 < col < len(self.headers):
            # # self.beginResetModel()
            # item = index.internalPointer()
            # # print(data)
            # item.itemData = data
            # self.dirty = True
            self.dataChanged.emit(index, index)
            return True
        return False

    def flags(self, index):
        if not index.isValid():
            return Qt.ItemIsEnabled
        return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
        # Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled

    def index(self, row, column, parent=None, *args, **kwargs):
        if not self.hasIndex(row, column, parent):
            return QModelIndex()

        return self.createIndex(row, column, parent)

    def parent(self, index=None):
        return QModelIndex()

    # def insertRows(self, row, count, parent=None):
    #     """
    #     插入行。
    #     :param row: 插入起始行。
    #     :param count: 插入行数量。
    #     :param parent:
    #     :return:
    #     """
    #     self.beginInsertRows(QModelIndex(), row, row + count - 1)
    #     for i in range(count):
    #         self.m_tableData.insert(row, ['CZ', '25', '男'])
    #     self.endInsertRows()
    #     return True
    #
    # def removeRows(self, row, count, parent=None):
    #     self.beginRemoveRows(QModelIndex(), 0, row + count - 1)
    #     for i in range(count):
    #         self.m_tableData.pop(row + count - 1 - i)  # 倒着删
    #     self.endRemoveRows()
    #
    # def clearView(self):
    #     self.removeRows(0, self.rowCount(), QModelIndex())


class SortProxyModel(QSortFilterProxyModel):
    """
    排序代理
    """

    def __init__(self, parent=None):
        super().__init__(parent)

        self.m_filter_columns = set()
        self.m_filter_map = dict()
        self.m_accepts_column = set()

        self.m_columns_filter = list()
    # def lessThan(self, left_index, right_index):
    #     """
    #     比较方法
    #     用于判断紧邻的两个数据的大小
    #     """
    #     #
    #     # # 获取相邻的两个QVariant对象
    #     left_var = left_index.data(Qt.DisplayRole)
    #     right_var = right_index.data(Qt.DisplayRole)
    #     #
    #     # # 转化为Python对象
    #     # left_str = left_var.toPyObject()
    #     # right_str = right_var.toPyObject()
    #     # print(type(left_index))
    #     # 转换为int
    #     # left_int = int(left_var)
    #     # right_int = int(right_var)
    #
    #     # 从方法名已经看出来，只要返回左是否比右小的bool值就行
    #     return (left_var < right_var)

    def filterAcceptsRow(self, src_row, src_parent):
        """
        过滤接收的行
        """
        # 获取数据Model
        # src_model = self.sourceModel()
        # 获得当前行的索引，0为列，我们目前只有一列，所以用第一列，也就是第0列
        # print("filterAcceptsRow", src_row, self.m_filter_map)
        for col in self.m_filter_columns:
            src_index = self.sourceModel().index(src_row, col, QModelIndex())

            # 获取当前索引的数据
            item_var = src_index.data(Qt.DisplayRole)
            return self.__filter(item_var, col)
        return True

    def filterAcceptsColumn(self, source_column, source_parent):
        # src_index = self.sourceModel().index(0, source_column, QModelIndex())
        if len(self.m_columns_filter) == 0:
            return True
        # print(source_column, self.m_columns_filter)
        if source_column +1 in self.m_columns_filter:
            return True
        return False

    def __filter(self, value, col):
        regex_str = ".*?(%s)" % self.m_filter_map[col]
        ret = re.match(regex_str, value)
        if ret:
            return True
        return False

    def set_filter(self, col, value):
        self.m_filter_map[col] = value
        self.m_filter_columns.add(col)
        self.invalidateFilter()

    def remove_filter(self, col):
        self.m_filter_map.pop(col)
        self.m_filter_columns.discard(col)

    def clean_filter(self):
        self.m_filter_map = dict()
        self.m_filter_columns = set()

    def set_column_index_filter(self, rows):
        self.m_columns_filter = rows
        self.invalidateFilter()
